package com.ruoyi.biz.service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.biz.domain.*;
import com.ruoyi.biz.enums.CostTypeEnum;
import com.ruoyi.biz.enums.ProjectStatusEnum;
import com.ruoyi.biz.mapper.*;
import com.ruoyi.biz.model.dto.BizProjectDto;
import com.ruoyi.biz.model.dto.ScoreDto;
import com.ruoyi.biz.model.dto.UpdateStatusDto;
import com.ruoyi.biz.model.req.*;
import com.ruoyi.biz.model.resp.*;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.RoleConstants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;

import java.util.stream.Collectors;

import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import static com.ruoyi.common.utils.SecurityUtils.getDeptId;
import static com.ruoyi.common.utils.SecurityUtils.getUserId;


/**
 * 项目信息Service业务层处理
 *
 * @author tianl
 * @date 2024-12-20
 */
@Slf4j
@Service
public class BizProjectService extends ServiceImpl<BizProjectMapper, BizProject> {
    @Autowired
    private BizProjectPlanService bizProjectPlanService;
    @Autowired
    private BizCostMapper bizCostMapper;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private BizReceiptMapper bizReceiptMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private BizInvoiceMapper bizInvoiceMapper;
    @Autowired
    private BizTopicMapper bizTopicMapper;
    @Autowired
    private BizProjectPlanMapper bizProjectPlanMapper;
    @Autowired
    private BizInvoiceHeaderService bizInvoiceHeaderService;
    @Autowired
    private BizTopicService bizTopicService;
    @Autowired
    private BizChannelMapper bizChannelMapper;
    @Autowired
    private BizTrusteeMapper bizTrusteeMapper;
    @Autowired
    private BizCostService bizCostService;

    /**
     * 分页查询项目信息
     */
    @DataScope(userAlias = "t", deptAlias = "t", enforceAlias = "t")
    public IPage<BizProjectResp> listPage(BizProjectReq req) {
        req.sort();
        req.getParams().put("userId", getUserId());
        IPage<BizProjectResp> page = baseMapper.list(PageUtils.page(), req);
        List<Long> projectIds = page.getRecords().stream().map(BizProjectResp::getId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(projectIds)) {
            String difficultDept = configService.selectConfigByKey("biz.project.difficult.dept");
            SysDept sysDept = sysDeptMapper.selectDeptByName(difficultDept);

            List<BizTopicResp> topicList = bizTopicService.listByProjectIds(projectIds);
            Map<Long, List<BizTopicResp>> mapProject = topicList.stream().collect(Collectors.groupingBy(BizTopicResp::getProjectId));
            for (BizProjectResp resp : page.getRecords()) {
                resp.setTopicList(mapProject.get(resp.getId()));
                if (resp.getUserId() != null && resp.getUserId().equals(getUserId())) {
                    resp.setCreateScoreAuth(true);
                }
                if (resp.getTransactorId() != null && resp.getTransactorId().equals(getUserId())) {
                    resp.setManagerScoreAuth(true);
                }
                if (resp.getEnforceDeptId() != null && sysDept != null && resp.getEnforceDeptId().equals(sysDept.getDeptId())) {
                    resp.setZgAuth(true);
                }
                if (resp.getPriority() != null && (resp.getPriority().equals("1") || resp.getPriority().equals("2"))) {
                    if (SecurityUtils.hasRoles(RoleConstants.ROLE_CEO, RoleConstants.ROLE_CTO)) {
                        resp.setEditAuth(true);
                    } else {
                        resp.setEditAuth(false);
                    }
                }
            }
        }
        return page;
    }

    /**
     * 查询项目信息列表
     */
    @DataScope(userAlias = "t", deptAlias = "t", enforceAlias = "t")
    public List<BizProjectSimpleResp> listAll(BizProjectReq req) {
        req.sort();
        req.getParams().put("userId", getUserId());
        return baseMapper.listAll(req);
    }

    @DataScope(userAlias = "t", deptAlias = "t", enforceAlias = "t")
    public List<BizProjectResp> list(BizProjectReq req) {
        req.sort();
        req.getParams().put("userId", getUserId());
        return baseMapper.list(req);
    }

    @DataScope(userAlias = "t", deptAlias = "t", enforceAlias = "t")
    public List<BizProject> listStat(StatReq req) {
        req.getParams().put("userId", getUserId());
        return baseMapper.listStat(req);
    }

    @DataScope(userAlias = "t", deptAlias = "t", enforceAlias = "t")
    public List<BizProjectResp> listStat2(StatReq req) {
        req.getParams().put("userId", getUserId());
        return baseMapper.listStat2(req);
    }

    @DataScope(userAlias = "t", deptAlias = "t", enforceAlias = "t")
    public List<BizProjectResp> listStatResp(StatReq req) {
        req.getParams().put("userId", getUserId());
        return baseMapper.listStatResp(req);
    }

    /**
     * 根据ID查询
     */
    public BizProjectResp selectById(Long id) {
        BizProjectResp resp = baseMapper.findDetail(id);
        List<BizProjectPlan> projectPlanList = bizProjectPlanService.listByProjectId(id);
        List<BizProjectPlan> progressList = projectPlanList.stream().filter(r -> r.getType().equals(0)).collect(Collectors.toList());
        List<BizProjectPlan> invoiceList = projectPlanList.stream().filter(r -> r.getType().equals(1)).collect(Collectors.toList());
        resp.setProgressList(progressList);
        resp.setInvoiceList(invoiceList);
        return resp;
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateZg(BizProjectDto bizProject) {
        BizProject old = selectById(bizProject.getId());
        if (old == null) {
            throw new ServiceException("项目信息异常");
        }
        String difficultLevel = configService.selectConfigByKey("biz.project.difficult.level");
        String difficultDept = configService.selectConfigByKey("biz.project.difficult.dept");
        SysDept sysDept = sysDeptMapper.selectDeptByName(difficultDept);
        if (sysDept == null) {
            throw new ServiceException("无部门信息");
        }
        if (StringUtils.isNotBlank(difficultLevel)) {
            old.setLevel(difficultLevel);
        }
        old.setEnforceDeptId(sysDept.getDeptId());
        baseMapper.updateById(old);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(UpdateStatusDto bizProject) {
        BizProject old = selectById(bizProject.getId());
        if (old == null) {
            throw new ServiceException("项目信息异常");
        }
        if (!old.getProjectStatus().equals(bizProject.getOldStatus())) {
            throw new ServiceException("项目状态已变更，请刷新重试");
        }
        old.setProjectStatus(bizProject.getProjectStatus());
        baseMapper.updateById(old);
    }

    /**
     * 新增修改项目信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void beforeSave(BizProjectDto bizProject) {
        if (bizProject.getSignTime() != null && bizProject.getSignTime().compareTo(DateUtils.getNowDate()) > 0) {
            throw new ServiceException("签约时间不能晚于当前时间");
        }
        boolean updateAmount = false;
        if (bizProject.getId() != null) {
            BizProject old = selectById(bizProject.getId());
            if (old.getTotalAmount().compareTo(bizProject.getTotalAmount()) != 0
                    || old.getRealAmount().compareTo(bizProject.getRealAmount()) != 0) {
                updateAmount = true;
            }
            bizProject.setUpdateTime(DateUtils.getNowDate());
        } else {
            updateAmount = true;
            bizProject.setCreateTime(DateUtils.getNowDate());
            bizProject.setUpdateTime(DateUtils.getNowDate());
            bizProject.setUserId(getUserId());
            bizProject.setDeptId(getDeptId());
        }
        if (bizProject.getChannelId() != null && bizProject.getChannelId() < 0) {
            if (StringUtils.isBlank(bizProject.getChannelPhone())) {
                throw new ServiceException("请填写渠道方联系方式");
            }
            BizChannel bizChannel = bizChannelMapper.findByPhone(bizProject.getChannelPhone());
            if (bizChannel == null) {
                bizChannel = new BizChannel();
                bizChannel.setContacts(bizProject.getChannelContacts());
                bizChannel.setPhone(bizProject.getChannelPhone());
                bizChannel.setUserId(getUserId());
                bizChannel.setCreateTime(DateUtils.getNowDate());
                bizChannel.setUpdateTime(DateUtils.getNowDate());
                bizChannelMapper.insert(bizChannel);
            } else if (bizProject.getChannelId() == null && !bizChannel.getContacts().equals(bizProject.getChannelContacts())) {
                throw new ServiceException("存在其他渠道方使用该联系方式");
            }
            bizProject.setChannelId(bizChannel.getId());
        }
        if (bizProject.getPrincipalId() != null && bizProject.getPrincipalId() < 0) {
            BizInvoiceHeader bizInvoiceHeader = bizInvoiceHeaderService.findByName(bizProject.getPrincipalName());
            if (bizInvoiceHeader == null) {
                bizInvoiceHeader = new BizInvoiceHeader();
                bizInvoiceHeader.setHeaderTitle(bizProject.getPrincipalName());
                bizInvoiceHeader.setCompanyName(bizProject.getPrincipalName());
                bizInvoiceHeader.setRegisteredAddr(bizProject.getPrincipalAddr());
                bizInvoiceHeader.setUsci(bizProject.getPrincipalUsci());
                bizInvoiceHeader.setContacts(bizProject.getPrincipalContacts());
                bizInvoiceHeader.setPhone(bizProject.getPrincipalPhone());
                bizInvoiceHeaderService.save(bizInvoiceHeader);
            }
            bizProject.setPrincipalId(bizInvoiceHeader.getId());
        }
        if (bizProject.getDeadline() != null
                && bizProject.getProjectStatus().equals(ProjectStatusEnum.OVERDUE.getCode())
                && bizProject.getDeadline().compareTo(new Date()) > 0) {
            //将逾期恢复成进行中
            bizProject.setProjectStatus(ProjectStatusEnum.DOING.getCode());
        }
        if (bizProject.getDeadline() != null
                && bizProject.getProjectStatus().equals(ProjectStatusEnum.DOING.getCode())
                && bizProject.getDeadline().compareTo(new Date()) <= 0) {
            //进行中变成逾期
            bizProject.setProjectStatus(ProjectStatusEnum.OVERDUE.getCode());
        }
        saveOrUpdate(bizProject);

        bizProjectPlanService.remove(new LambdaQueryWrapper<BizProjectPlan>()
                .and(i -> i.eq(BizProjectPlan::getProjectId, bizProject.getId())));
        List<BizProjectPlan> projectPlanList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(bizProject.getProgressList())) {
            bizProject.getProgressList().forEach(r -> {
                r.setId(null);
                r.setProjectId(bizProject.getId());
                r.setType(0);
            });
            projectPlanList.addAll(bizProject.getProgressList());
        }
        if (!CollectionUtils.isEmpty(bizProject.getInvoiceList())) {
            bizProject.getInvoiceList().forEach(r -> {
                r.setId(null);
                r.setProjectId(bizProject.getId());
                r.setType(1);
            });
            projectPlanList.addAll(bizProject.getInvoiceList());
        }
        if (!CollectionUtils.isEmpty(projectPlanList)) {
            bizProjectPlanService.saveBatch(projectPlanList);
        }
        if (bizProject.getRealAmount() == null) {
            bizProject.setRealAmount(bizProject.getTotalAmount());
        }
        if (updateAmount) {
            bizProject.setRealIncome(bizProject.getRealAmount());
            bizCostService.delByProjectId(bizProject.getId());
            BigDecimal channelMoney = BigDecimal.ZERO;
            if (bizProject.getTotalAmount() != null && bizProject.getRealAmount() != null) {
                channelMoney = bizProject.getTotalAmount().subtract(bizProject.getRealAmount());
            }
            BigDecimal taxMoney = BigDecimal.ZERO;
            if (bizProject.getTrusteeId() != null) {
                BizTrustee trustee = bizTrusteeMapper.selectById(bizProject.getTrusteeId());
                if (trustee != null) {
                    taxMoney = channelMoney.multiply(trustee.getTaxProportion());
                }
            }
            bizProject.setChannelCost(channelMoney);
            bizProject.setChannelTax(taxMoney);
            bizProject.setRealIncome(bizProject.getRealAmount().subtract(taxMoney));
            saveOrUpdate(bizProject);
            bizCostService.calcProjectDefault(bizProject.getId(), bizProject.getUserId());
            calcProjectCost(bizProject.getId());
        }

        calcProjectReceipt(bizProject.getId());
    }

    /**
     * 批量删除项目信息
     */
    @Transactional(rollbackFor = Exception.class)
    public int deleteByIds(List<Long> ids) {
        for (Long id : ids) {
            BizProject model = selectById(id);
            if (model == null) {
                continue;
            }
            LambdaQueryWrapper<BizCost> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.and(i -> i.eq(BizCost::getProjectId, id));
            bizCostMapper.delete(wrapper1);
            if (model.getProjectStatus().equals(ProjectStatusEnum.SAVE.getCode())) {
                LambdaQueryWrapper<BizTopic> wrapper0 = new LambdaQueryWrapper<>();
                wrapper0.and(i -> i.eq(BizTopic::getProjectId, id));
                bizTopicMapper.delete(wrapper0);
                LambdaQueryWrapper<BizInvoice> wrapper2 = new LambdaQueryWrapper<>();
                wrapper2.and(i -> i.eq(BizInvoice::getProjectId, id));
                bizInvoiceMapper.delete(wrapper2);
                LambdaQueryWrapper<BizReceipt> wrapper3 = new LambdaQueryWrapper<>();
                wrapper3.and(i -> i.eq(BizReceipt::getProjectId, id));
                bizReceiptMapper.delete(wrapper3);
            } else {
                LambdaQueryWrapper<BizTopic> wrapper0 = new LambdaQueryWrapper<>();
                wrapper0.and(i -> i.eq(BizTopic::getProjectId, id));
                long count0 = bizTopicMapper.selectCount(wrapper0);
                if (count0 > 0) {
                    throw new ServiceException(model.getProjectName() + "下存在子课题信息，不允许删除！");
                }
                LambdaQueryWrapper<BizInvoice> wrapper2 = new LambdaQueryWrapper<>();
                wrapper2.and(i -> i.eq(BizInvoice::getProjectId, id));
                long count2 = bizInvoiceMapper.selectCount(wrapper2);
                if (count2 > 0) {
                    throw new ServiceException(model.getProjectName() + "下存在开票信息，不允许删除！");
                }
                LambdaQueryWrapper<BizReceipt> wrapper3 = new LambdaQueryWrapper<>();
                wrapper3.and(i -> i.eq(BizReceipt::getProjectId, id));
                long count3 = bizReceiptMapper.selectCount(wrapper3);
                if (count3 > 0) {
                    throw new ServiceException(model.getProjectName() + "下存在收款登记信息，不允许删除！");
                }
            }
        }
        LambdaQueryWrapper<BizProjectPlan> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(i -> i.in(BizProjectPlan::getProjectId, ids));
        bizProjectPlanMapper.delete(wrapper);
        return baseMapper.deleteBatchIds(ids);
    }


    /**
     * 成本计算
     *
     * @param projectId
     */
    @Transactional(rollbackFor = Exception.class)
    public void calcProjectCost(Long projectId) {
        BigDecimal realIncome = BigDecimal.ZERO;
        BizProject project = selectById(projectId);
        if (project == null) {
            throw new ServiceException("项目信息错误");
        }
        if (project.getRealIncome() != null) {
            realIncome = project.getRealIncome();
        }
        List<BizCost> costList = bizCostMapper.listByProjectId(projectId);
        BigDecimal totalCost = costList.stream().map(BizCost::getCostMoney).reduce(BigDecimal.ZERO, BigDecimal::add); // 计算总和
        BigDecimal perMoney = costList.stream().filter(r ->
                r.getCostType().equals(CostTypeEnum.COST_MANAGE_PER.getCode()) || r.getCostType().equals(CostTypeEnum.COST_AGREE_PER.getCode())
        ).map(BizCost::getCostMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal perMoney1 = costList.stream().filter(r ->
                r.getCostType().equals(CostTypeEnum.COST_MANAGE_PER.getCode())
        ).map(BizCost::getCostMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal perMoney2 = costList.stream().filter(r ->
                r.getCostType().equals(CostTypeEnum.COST_AGREE_PER.getCode())
        ).map(BizCost::getCostMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        project.setBaseCost(totalCost);
        BigDecimal profitMoney = realIncome.subtract(totalCost);
        project.setProfit(profitMoney);
        project.setPerformance(perMoney);
        project.setManagePerformance(perMoney1);
        project.setAgreePerformance(perMoney2);
        String valStr2 = configService.selectConfigByKey("biz.project.marketperformance.proportion");
        BigDecimal marketProportion = new BigDecimal("0.3");
        if (valStr2 != null) {
            try {
                marketProportion = new BigDecimal(valStr2);
            } catch (Exception e) {
                log.error("市场绩效比例配置有误！！！", e);
            }
        }
        BigDecimal marketPerformance = profitMoney.multiply(marketProportion);
        if (project.getManagerScore() != null && project.getManagerScore().compareTo(BigDecimal.valueOf(80)) >= 0) {
            marketPerformance = marketPerformance.multiply(project.getManagerScore().divide(BigDecimal.valueOf(100))).setScale(2, RoundingMode.HALF_UP);
        }
        project.setMarketPerformance(marketPerformance);
        project.setFinalProfit(profitMoney.subtract(project.getMarketPerformance()));
        saveOrUpdate(project);
    }

    /**
     * 收款计算
     *
     * @param projectId
     */
    @Transactional(rollbackFor = Exception.class)
    public void calcProjectReceipt(Long projectId) {
        BizProject project = selectById(projectId);
        if (project == null) {
            throw new ServiceException("项目信息错误");
        }
        BigDecimal totalAmount = BigDecimal.ZERO;
        if (project.getTotalAmount() != null) {
            totalAmount = project.getTotalAmount();
        }
        List<BizReceiptResp> receipts = bizReceiptMapper.listByProjectIds(Arrays.asList(projectId));
        BigDecimal total = receipts.stream().filter(r -> r.getStatus() == 1).map(BizReceiptResp::getReceiptMoney).reduce(BigDecimal.ZERO, BigDecimal::add); // 计算总和
        BigDecimal sub = totalAmount.subtract(total);
        project.setReceivedAmount(total);
        project.setUnReceivedAmount(sub);
        if (sub.compareTo(BigDecimal.ZERO) == 0) {
            if (!CollectionUtils.isEmpty(receipts)) {
                BizReceiptResp max = receipts.stream()
                        .max(Comparator.comparing(BizReceipt::getReceiptTime))
                        .orElse(null);
                project.setReceiptAllDate(max.getReceiptTime());
            }
        }
        if (project.getProjectStatus().compareTo(ProjectStatusEnum.DG.getCode()) < 0) {
            if (total.equals(project.getTotalAmount())) {
                project.setProjectStatus(ProjectStatusEnum.DONE.getCode());
                project.setFinishTime(new Date());
            }
        }
        saveOrUpdate(project);
    }

    @Transactional(rollbackFor = Exception.class)
    public void score(ScoreDto dto) {
        BizProject model = selectById(dto.getProjectId());
        if (model == null) {
            throw new ServiceException("项目信息错误");
        }
        if (dto.getType() == 0) {
            model.setCreateScore(dto.getScore());
            List<BizCost> costList = bizCostMapper.listByProjectIdType(dto.getProjectId()
                    , Arrays.asList(CostTypeEnum.COST_AGREE_PER.getCode()));
            for (BizCost bizCost : costList) {
                bizCost.setCostMoney(bizCost.getCostMoneyOriginal().multiply(model.getCreateScore().divide(BigDecimal.valueOf(100))).setScale(2, RoundingMode.HALF_UP));
                bizCostMapper.updateById(bizCost);
            }
        } else {
            model.setManagerScore(dto.getScore());
        }
        saveOrUpdate(model);
        calcProjectCost(dto.getProjectId());
    }
}
